package com.lzh.chatnote.user.service;

import cn.hutool.core.thread.NamedThreadFactory;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.google.gson.reflect.TypeToken;
import com.lzh.chatnote.common.config.threadPoolConfig.GlobalUncaughtExceptionHandler;
import com.lzh.chatnote.user.dao.UserDao;
import com.lzh.chatnote.user.domain.entity.IpInfo;
import com.lzh.chatnote.user.domain.entity.IpInfoDetail;
import com.lzh.chatnote.user.domain.entity.User;
import com.lzh.chatnote.user.domain.vo.response.user.IpInfoData;
import com.lzh.chatnote.user.domain.vo.response.user.UserIpInfoResp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class IpQueryServiceImpl implements IpQueryService, DisposableBean {

    //定义线程池单个线程
    private static final // 自定义线程池
            ThreadPoolExecutor customThreadPool = new ThreadPoolExecutor(1,                          // 核心线程数
            1,                         // 最大线程数
            0L,                        // 空闲线程存活时间
            TimeUnit.SECONDS,           // 时间单位
            new LinkedBlockingQueue<Runnable>(200), // 工作队列
            //自定义线程工厂，打印日志，不然子线程日志会被丢弃
            new NamedThreadFactory("refresh-ipDetail",null, false,
                    new GlobalUncaughtExceptionHandler())
    );

    @Resource
    private UserDao userDao;

    public void refreshIpDetail(Long uuid) {
        customThreadPool.execute(() -> {
           //先获取用户信息
            User userInfo = userDao.getById(uuid);
            IpInfo ipInfo = userInfo.getIpInfo();
            if(Objects.isNull(ipInfo)){
                return;
            }
           //获取要刷新的ip
           String ip =  ipInfo.tryGetReflushIp(ipInfo);
           if(StrUtil.isBlank(ip)){
               //当前更新的ip和旧的ip一致，不更新
               return;
           }
           //获取ip信息详情
           IpInfoDetail  infoDetail =  tryGetInfoByIp(ip);
           if(Objects.nonNull(infoDetail)){
               ipInfo.reflushIpDetail(infoDetail);
               User update = new User();
               update.setId(uuid);
               update.setIpInfo(ipInfo);
               userDao.updateById(update);
               //todo
           }else{
               log.error("获取ip信息失败");
           }
        });
    }

    private IpInfoDetail tryGetInfoByIp(String ip) {
        IpInfoData ipInfoData =   tryGetIpInfoData(ip);
        if(Objects.isNull(ipInfoData)){
            return null;
        }

        return new IpInfoDetail(ipInfoData.getIp(),ipInfoData.getCountry(),ipInfoData.getCountry_id(),
                ipInfoData.getRegion(),ipInfoData.getRegion_id(),ipInfoData.getCity(),ipInfoData.getCountry_id(),
                ipInfoData.getIsp(),ipInfoData.getIsp_id());
    }

    //通过淘宝免费接口获取ip信息
    private  IpInfoData tryGetIpInfoData(String ip) {
        for (int i = 0; i < 3; i++) {
            String requestUrl = String.format("https://ip.taobao.com/outGetIpInfo?ip=%s&accessKey=alibaba-inc", ip);
            String jsonStr = HttpUtil.get(requestUrl);
            Type type = new TypeToken<UserIpInfoResp>() {}.getType();
            UserIpInfoResp userIpInfoResp = JSONUtil.toBean(jsonStr, type, false);
            IpInfoData ipInfoData = userIpInfoResp.getData();
            if(Objects.nonNull(ipInfoData)){
                return ipInfoData;
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        return null;
    }


    @Override
    public void destroy() throws Exception {
        //优雅停机,处理线程没有处理完成的线程
        customThreadPool.shutdown();
        if (!customThreadPool.awaitTermination(30, TimeUnit.SECONDS)) {//最多等30秒，处理不完就拉倒
            if (log.isErrorEnabled()) {
                log.error("Timed out while waiting for executor [{}] to terminate", customThreadPool);
            }
        }

    }
}
